﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Collections;

namespace Xceed.Silverlight.Data
{
  internal static class ResultsExtensions
  {
    internal static int GetMoveUnit( this MoveAndFetchResult moveResult )
    {
      return DataUtils.GetUnit( moveResult.ExpectedMoveCount );
    }

    internal static int GetFetchUnit( this MoveAndFetchResult fetchResult )
    {
      return DataUtils.GetUnit( fetchResult.ExpectedFetchCount );
    }

    internal static Nullable<long> GetMoveDisplacement( this MoveAndFetchResult moveResult )
    {
      return moveResult.ActualMoveCount;
    }

    internal static int GetFetchDisplacement( this MoveAndFetchResult moveAndFetchResult )
    {
      return ResultsExtensions.GetFetchDisplacement(
        moveAndFetchResult.FetchedObjects,
        moveAndFetchResult.ExpectedFetchCount );
    }

    internal static int GetFetchDisplacement( this GroupFetchResult groupFetchResult, int expectedFetchCount )
    {
      return ResultsExtensions.GetFetchDisplacement(
        DataUtils.ConvertToNonGeneric<DataPath>( groupFetchResult.FetchedItems ),
        expectedFetchCount );
    }

    internal static int GetFetchDisplacement( ICollection fetchedObjects, int expectedFetchCount )
    {
      int fetchMove = 0;

      if( fetchedObjects != null )
      {
        int fetchUnit = DataUtils.GetUnit( expectedFetchCount );

        fetchMove = Math.Max( 0, fetchedObjects.Count - 1 ) * fetchUnit;

        if( fetchedObjects.Count != Math.Abs( expectedFetchCount ) )
        {
          //This means that the fetch ended out of bound, where there is no data.
          fetchMove += fetchUnit;
        }
      }

      return fetchMove;
    }

    internal static EstimateInt64 GetMaximumFetchCount( this JumpMoveAndFetchResult jumpResult )
    {
      if( jumpResult.FetchedObjects == null )
        return null;

      if( jumpResult.ExpectedFetchCount == 0 )
        return null;

      if( jumpResult.FetchedObjects.Count < Math.Abs( jumpResult.ExpectedFetchCount ) )
        return new EstimateInt64( jumpResult.FetchedObjects.Count * jumpResult.GetFetchUnit(), false );

      EstimateInt64 limitOffset = null;

      if( jumpResult.EndPositionOffset != null )
      {
        ReferencePoint neededReferencePoint = ( jumpResult.GetFetchUnit() == 1 )
        ? ReferencePoint.AfterLast
        : ReferencePoint.BeforeFirst;

        if( jumpResult.EndPositionOffset.ReferencePosition == neededReferencePoint )
        {
          limitOffset = jumpResult.EndPositionOffset.Value;
        }
        else if( jumpResult.TotalCount != null )
        {
          limitOffset = jumpResult.TotalCount - jumpResult.EndPositionOffset.Value;
          limitOffset += 1;
        }

        long maximumFetchCount = Math.Abs( jumpResult.ExpectedFetchCount ) + ( limitOffset.Value - 1 );

        return new EstimateInt64( maximumFetchCount * jumpResult.GetFetchUnit(), limitOffset.IsEstimate );
      }

      return null;
    }

    internal static EstimateInt64 GetTotalDisplacement( this MoveAndFetchResult moveAndFetchResult )
    {

      //A "null" moveDisplacement indicates a failed move operation with no information
      //on how much of the move succeeded. We use ExpectedMoveCount as the worst case scenario.
      //Zero could infer a shorter data source than expected.
      Nullable<long> moveDisplacement = moveAndFetchResult.GetMoveDisplacement();
      int fetchDisplacement = moveAndFetchResult.GetFetchDisplacement();

      if( moveDisplacement == null )
      {
        return new EstimateInt64( moveAndFetchResult.ExpectedMoveCount + fetchDisplacement, true );
      }
      else
      {
        return new EstimateInt64( moveDisplacement.Value + fetchDisplacement, moveAndFetchResult.ApproximateMove );
      }
    }

    internal static JumpMoveAndFetchParameters GetParameters( this JumpMoveAndFetchResult result )
    {
      return new JumpMoveAndFetchParameters( result.SourcePosition, result.ExpectedMoveCount, result.ExpectedFetchCount, result.ApproximateMove );
    }


    internal static bool IsMovingForward( this MoveAndFetchResult fetchResult )
    {
      if( fetchResult.ExpectedMoveCount == 0 )
        throw new InvalidOperationException( "No moves were made with this operation." );

      return ( fetchResult.ExpectedMoveCount > 0 );
    }

    internal static bool IsFetchingForward( this MoveAndFetchResult fetchResult )
    {
      if( fetchResult.ExpectedFetchCount == 0 )
        throw new InvalidOperationException( "No fetches were made with this operation." );

      return ( fetchResult.ExpectedFetchCount > 0 );
    }

    internal static bool IsMoveSuccess( this MoveAndFetchResult moveAndFetchResult )
    {
      return ( moveAndFetchResult.FetchedObjects != null );
    }

    internal static bool IsFetchSuccess( this MoveAndFetchResult moveAndFetchResult )
    {
      return ( moveAndFetchResult.FetchedObjects != null
        && moveAndFetchResult.FetchedObjects.Count == moveAndFetchResult.ExpectedFetchCount );
    }
  }
}
